Telegram Group & Telegram Channel
Making Deep Learning Go Brrrr From First Principles

Предлагаю сегодня посмотреть на третий пост от Horace He - разработчика Pytorch - на этот раз по поводу выжимания производительности из говнокода. Мы уже разбирали его пост на тему скорости умножения матриц разного размера, а также о том, почему матрицы из нулей перемножаются быстрее остальных.

В этой статье (2020) проанализировали фактические вычисления и реальные временные затраты в имплементации BERT и получили, что хоть матричные умножения и составляют 99.8% вычислений, на них уходит лишь 61% времени - остальное уходит на element-wise операции / нормализации. Huh?

У любого Deep Learning графа можно выделить 3 вида боттлнеков. Очень полезным будет понимать, какой из боттлнеков является наиболее актуальным в каждом конкретном сетапе. Давайте разберём их по порядку.

Compute - временные затраты на фактическое выполнение вычислений на GPU

В принципе, если в вашей схеме compute - главный боттлнек, то с этим уже можно поздравить - такое бывает нечасто. Но и тут не всё так просто.
В современных GPU есть так называемые Tensor Cores - процессоры, созданные только для умножения матриц. Они выдают в 15 раз больше флопсов, чем обычные ядра, таким образом, все остальные вычисления получают большой штраф к скорости.

Однако, в упомянутом BERT все эти операции выполнялись в сотни раз медленнее, чем матричные умножения, с точки зрения флопсов. И если даже дефолтнейший трансформер упирается в другие боттлнеки, то ваш говнокод явно страдает в основном от них.

Bandwidth - временные затраты на движение данных внутри GPU

Как уже было упомянуто в посте про матрицы, движение данных туда-сюда для вычислений занимает жирный кусок времени выполнения. Чтобы его минимизировать, необходимо фьюзить операции - выполнять много вычислений над куском данных за раз. Есть много уровней болота, на которые можно опуститься. Из элементарного - удалите из своего кода x1 = x.cos() \n x2 = x1.cos() и замените на x2 = x.cos().cos(). Можно фьюзить нормализации с соседними операциями, применять автоматические фьюзеры/компиляторы, ну, а если вы псих, то можно написать свой CUDA kernel на Triton (сам не пробовал).

В посте ссылка на colab
, в котором проведён следующий эксперимент - берём тензор размера ~миллион и умножаем на 2 несколько раз с включенным компилятором, который объединяет умножения в один поход в GPU, Что бы вы думали? 16 умножений работают с той же скоростью, что и одно. Лишь после 64 умножений мы начинаем упираться в компьют.

Overhead - все остальные затраты

На прикреплённой картинке можно увидеть результат профайлинга пайторча, который производит единичное сложение. Итак, A100 умеет выдавать 312 терафлопсов, чистый питон выдаёт 32 мегафлопсов при сложении, а вот пайторч для вас сделает это лишь 280 тысяч раз.

Пайторч и другие фреймворки не оптимизированы под выполнение маленьких операций, их приоритет - гибкость и комфорт для разработчика, а также скорость выполнения больших операций. Вы можете просто попросить Pytorch посчитать a + b, и под капотом он сделает тонну работы, которая позволяет вам не указывать все типы данных, шейпы и т.д. вручную.

Уменьшать overhead можно тем же методом - используя соответствующий компилятор графа - если это касается самого фреймворка, ну и писать нормальный код, если речь про остальное. Так что, как видите, всё очень просто.

@knowledge_accumulator



tg-me.com/knowledge_accumulator/257
Create:
Last Update:

Making Deep Learning Go Brrrr From First Principles

Предлагаю сегодня посмотреть на третий пост от Horace He - разработчика Pytorch - на этот раз по поводу выжимания производительности из говнокода. Мы уже разбирали его пост на тему скорости умножения матриц разного размера, а также о том, почему матрицы из нулей перемножаются быстрее остальных.

В этой статье (2020) проанализировали фактические вычисления и реальные временные затраты в имплементации BERT и получили, что хоть матричные умножения и составляют 99.8% вычислений, на них уходит лишь 61% времени - остальное уходит на element-wise операции / нормализации. Huh?

У любого Deep Learning графа можно выделить 3 вида боттлнеков. Очень полезным будет понимать, какой из боттлнеков является наиболее актуальным в каждом конкретном сетапе. Давайте разберём их по порядку.

Compute - временные затраты на фактическое выполнение вычислений на GPU

В принципе, если в вашей схеме compute - главный боттлнек, то с этим уже можно поздравить - такое бывает нечасто. Но и тут не всё так просто.
В современных GPU есть так называемые Tensor Cores - процессоры, созданные только для умножения матриц. Они выдают в 15 раз больше флопсов, чем обычные ядра, таким образом, все остальные вычисления получают большой штраф к скорости.

Однако, в упомянутом BERT все эти операции выполнялись в сотни раз медленнее, чем матричные умножения, с точки зрения флопсов. И если даже дефолтнейший трансформер упирается в другие боттлнеки, то ваш говнокод явно страдает в основном от них.

Bandwidth - временные затраты на движение данных внутри GPU

Как уже было упомянуто в посте про матрицы, движение данных туда-сюда для вычислений занимает жирный кусок времени выполнения. Чтобы его минимизировать, необходимо фьюзить операции - выполнять много вычислений над куском данных за раз. Есть много уровней болота, на которые можно опуститься. Из элементарного - удалите из своего кода x1 = x.cos() \n x2 = x1.cos() и замените на x2 = x.cos().cos(). Можно фьюзить нормализации с соседними операциями, применять автоматические фьюзеры/компиляторы, ну, а если вы псих, то можно написать свой CUDA kernel на Triton (сам не пробовал).

В посте ссылка на colab
, в котором проведён следующий эксперимент - берём тензор размера ~миллион и умножаем на 2 несколько раз с включенным компилятором, который объединяет умножения в один поход в GPU, Что бы вы думали? 16 умножений работают с той же скоростью, что и одно. Лишь после 64 умножений мы начинаем упираться в компьют.

Overhead - все остальные затраты

На прикреплённой картинке можно увидеть результат профайлинга пайторча, который производит единичное сложение. Итак, A100 умеет выдавать 312 терафлопсов, чистый питон выдаёт 32 мегафлопсов при сложении, а вот пайторч для вас сделает это лишь 280 тысяч раз.

Пайторч и другие фреймворки не оптимизированы под выполнение маленьких операций, их приоритет - гибкость и комфорт для разработчика, а также скорость выполнения больших операций. Вы можете просто попросить Pytorch посчитать a + b, и под капотом он сделает тонну работы, которая позволяет вам не указывать все типы данных, шейпы и т.д. вручную.

Уменьшать overhead можно тем же методом - используя соответствующий компилятор графа - если это касается самого фреймворка, ну и писать нормальный код, если речь про остальное. Так что, как видите, всё очень просто.

@knowledge_accumulator

BY Knowledge Accumulator




Share with your friend now:
tg-me.com/knowledge_accumulator/257

View MORE
Open in Telegram


Knowledge Accumulator Telegram | DID YOU KNOW?

Date: |

Importantly, that investor viewpoint is not new. It cycles in when conditions are right (and vice versa). It also brings the ineffective warnings of an overpriced market with it.Looking toward a good 2022 stock market, there is no apparent reason to expect these issues to change.

That growth environment will include rising inflation and interest rates. Those upward shifts naturally accompany healthy growth periods as the demand for resources, products and services rise. Importantly, the Federal Reserve has laid out the rationale for not interfering with that natural growth transition.It's not exactly a fad, but there is a widespread willingness to pay up for a growth story. Classic fundamental analysis takes a back seat. Even negative earnings are ignored. In fact, positive earnings seem to be a limiting measure, producing the question, "Is that all you've got?" The preference is a vision of untold riches when the exciting story plays out as expected.

Knowledge Accumulator from kr


Telegram Knowledge Accumulator
FROM USA